package com.jiang.demo.config.knife4j;

import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.jiang.demo.common.constans.Constant;
import com.jiang.demo.common.util.ReflectUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;

import java.lang.reflect.Field;
import java.util.Optional;

import static springfox.documentation.schema.Annotations.findPropertyAnnotation;
import static springfox.documentation.swagger.schema.ApiModelProperties.findApiModePropertyAnnotation;

/**
 * ---------------------------------------------------------------------------------------------------------------
 * - 2024-06-01 15:24 - jiangshaoneng -
 * ---------------------------------------------------------------------------------------------------------------
 * -      ██╗██╗ █████╗ ███╗   ██╗ ██████╗ ███████╗██╗  ██╗ █████╗  ██████╗ ███╗   ██╗███████╗███╗   ██╗ ██████╗
 * -      ██║██║██╔══██╗████╗  ██║██╔════╝ ██╔════╝██║  ██║██╔══██╗██╔═══██╗████╗  ██║██╔════╝████╗  ██║██╔════╝
 * -      ██║██║███████║██╔██╗ ██║██║  ███╗███████╗███████║███████║██║   ██║██╔██╗ ██║█████╗  ██╔██╗ ██║██║  ███╗
 * - ██   ██║██║██╔══██║██║╚██╗██║██║   ██║╚════██║██╔══██║██╔══██║██║   ██║██║╚██╗██║██╔══╝  ██║╚██╗██║██║   ██║
 * - ╚█████╔╝██║██║  ██║██║ ╚████║╚██████╔╝███████║██║  ██║██║  ██║╚██████╔╝██║ ╚████║███████╗██║ ╚████║╚██████╔╝
 * -  ╚════╝ ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚═╝  ╚═══╝╚══════╝╚═╝  ╚═══╝ ╚═════╝
 * ---------------------------------------------------------------------------------------------------------------
 * TODO
 * ---------------------------------------------------------------------------------------------------------------
 */
@Slf4j
@Component
public class Knife4jModelPropertyBuilderPlugin implements ModelPropertyBuilderPlugin {

    @Override
    public void apply(ModelPropertyContext context) {
        Optional<BeanPropertyDefinition> beanPropertyDefinitionOpt = context.getBeanPropertyDefinition();
        Optional<ApiModelProperty> annotation = Optional.empty();
        if (context.getAnnotatedElement().isPresent())
            annotation = annotation.map(Optional::of).orElse(findApiModePropertyAnnotation(context.getAnnotatedElement().get()));
        if (context.getBeanPropertyDefinition().isPresent())
            annotation = annotation.map(Optional::of).orElse(findPropertyAnnotation(context.getBeanPropertyDefinition().get(),ApiModelProperty.class));;

        if (annotation.isPresent() && beanPropertyDefinitionOpt.isPresent()) {
            // 自定义字段的顺序, 根据代码写的顺序生成
            positionBuilderPlugin(context, beanPropertyDefinitionOpt.get());
            // 自定义枚举展示
            enumBuilderPlugin(context, beanPropertyDefinitionOpt.get(), annotation.get());
        }
    }

    // 自定义字段的顺序, 根据代码写的顺序生成
    private void positionBuilderPlugin(ModelPropertyContext context, BeanPropertyDefinition beanPropertyDefinition){
        /*获取到注解字段*/
        AnnotatedField field = beanPropertyDefinition.getField();
        /*获取到字段所在的类*/
        Class<?> clazz = field.getDeclaringClass();
        /*获取类中所有字段*/
        Field[] declaredFields = ReflectUtil.getAllDeclaredFields(clazz);
        Field declaredField;
        /*获取当前字段的Field*/
        try {
            declaredField = clazz.getDeclaredField(field.getName());
        } catch (NoSuchFieldException | SecurityException e) {
            log.error("", e);
            return;
        }
        /*获取当前字段在数组中的位置。然后设置position属性*/
        int indexOf = ArrayUtils.indexOf(declaredFields, declaredField);
        if(Constant.BASE_ENTITY_SIMPLE_NAME.equals(clazz.getSimpleName())){ // 基类的放到最后面
            indexOf += 1000;
        }
        if (indexOf != -1) context.getBuilder().position(indexOf);
    }

    // 自定义枚举展示
    private void enumBuilderPlugin(ModelPropertyContext context, BeanPropertyDefinition beanPropertyDefinition, ApiModelProperty annotation){
        String joinText = ReflectUtil.joinText(annotation.notes(), annotation.value());
        if(StringUtils.isAllBlank(joinText)) return;
        final Class<?> fieldType = beanPropertyDefinition.getField().getRawType();
        final ResolvedType resolvedType = context.getResolver().resolve(fieldType);
        context.getBuilder().description(joinText).type(resolvedType);
    }




    @SuppressWarnings("all")
    @Override
    public boolean supports(DocumentationType delimiter) {
        return true;
    }
}

